﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using FastColoredTextBoxNS;
using System.Text.RegularExpressions;

namespace CsharpCodeGenerator
{
    public partial class Main : Form
    {
        //styles
        TextStyle BlueStyle = new TextStyle(Brushes.Blue, null, FontStyle.Regular);
        TextStyle BoldStyle = new TextStyle(null, null, FontStyle.Bold | FontStyle.Underline);
        TextStyle GrayStyle = new TextStyle(Brushes.Gray, null, FontStyle.Regular);
        TextStyle MagentaStyle = new TextStyle(Brushes.Magenta, null, FontStyle.Regular);
        TextStyle GreenStyle = new TextStyle(Brushes.Green, null, FontStyle.Italic);
        TextStyle BrownStyle = new TextStyle(Brushes.Brown, null, FontStyle.Italic);
        TextStyle MaroonStyle = new TextStyle(Brushes.Maroon, null, FontStyle.Regular);
        MarkerStyle SameWordsStyle = new MarkerStyle(new SolidBrush(Color.FromArgb(40, Color.Gray)));

        public Main()
        {
            InitializeComponent();

            InitStylesPriority();
            //            
            fctb.Text = @"Store Procedure and C# DAL, BLL Class Generator

BY DucNgo

E-mail: ducngo89@gmail.com

WebSite: http://mahan-web.ir

";
            //move caret to start text
            fctb.Selection.Start = Place.Empty;
            fctb.DoCaretVisible();
            fctb.IsChanged = false;
            fctb.ClearUndo();

            LoadSettings();
        }

        private void LoadSettings()
        {
            ConfigTemplate ct = Configuration.ReadConfig();


            Session.SaveInSession("Prefix", ct.StoredProceduresPrefix);
            Session.SaveInSession("AuthorName", ct.AuthorName);
            Session.SaveInSession("NullParamDefaultValues", ct.PassNullAsDefaultParamaeterValue);
            Session.SaveInSession("GenerateWrapperClass", ct.GenerateWrapperClass);
            Session.SaveInSession("WrapperClass_GenerateStaticMethods", ct.WrapperClass_GenerateStaticMethods);
            Session.SaveInSession("WrapperClass_NameSpace", ct.WrapperClass_NameSpace);

            Session.SaveInSession("AutoSaveWrapperClass", ct.AutoSaveWrapperClass);
            Session.SaveInSession("AutoSaveScript", ct.AutoSaveScript);

            Session.SaveInSession("GenerateDeleteRowProc", ct.GenerateDeleteRowProc);
            Session.SaveInSession("GenerateInsertProc", ct.GenerateInsertProc);
            Session.SaveInSession("GenerateSelectAllProc", ct.GenerateSelectAllProc);
            Session.SaveInSession("GenerateSelectRowByForeignKeyProc", ct.GenerateSelectRowByForeignKeyProc);
            Session.SaveInSession("GenerateSelectRowProc", ct.GenerateSelectRowProc);
            Session.SaveInSession("GenerateUpdateProc", ct.GenerateUpdateProc);

            Session.SaveInSession("SaveToFile", ct.SaveToFile);
            Session.SaveInSession("Namespace", ct.Namespace);
            Session.SaveInSession("GenEntity", ct.GenEntity);

        }

        private void InitStylesPriority()
        {
            fctb.ClearStylesBuffer();

            //add this style explicitly for drawing under other styles
            fctb.AddStyle(SameWordsStyle);
        }

        private void Authentication_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (Authentication.SelectedIndex == 1)
            {
                UserLabel.Enabled = true;
                PassLabel.Enabled = true;
                Password.Enabled = true;
                UserName.Enabled = true;
            }
            else
            {
                UserLabel.Enabled = false;
                PassLabel.Enabled = false;
                Password.Enabled = false;
                UserName.Enabled = false;
            }
        }

        private void Main_Load(object sender, EventArgs e)
        {
            Authentication.SelectedIndex = 0;
            this.Width = 430;
            this.Height = 300;
        }
        private string GetConnectionString(int AuthenticationType)
        {
            string connStr = string.Empty;

            if (AuthenticationType == 1)
            {
                connStr =
                    string.Format("Server={0:G};Database=master;User ID={1:G};Password={2:G};Trusted_Connection=False;",
                                  ServerName.Text, UserName.Text, Password.Text);
            }
            else
                connStr =
                    string.Format("Data Source={0:G};Initial Catalog=master;Integrated Security=SSPI;",
                                  ServerName.Text);

            return connStr;
        }

        private void Connect_Click(object sender, EventArgs e)
        {

            string conStr = GetConnectionString(Authentication.SelectedIndex);
            string Version = Helper.GetVersion(conStr);
            string Query = string.Empty;
            try
            {
                if (int.Parse(Version) <= 8)
                {
                    Query = Helper.Version2000;
                }
                else
                {
                    Query = Helper.Version2008;
                }

                IDataReader dr = Helper.GetDataBases(conStr, Query);
                while (dr.Read())
                {
                    treeView1.Nodes.Add(dr["Text"].ToString());

                }
                if (treeView1.Nodes.Count > 0)
                {
                    foreach (TreeNode item in treeView1.Nodes)
                    {
                        IDataReader treeDr = Helper.GetTableLists(conStr, item.Text, "Tables");

                        while (treeDr.Read())
                        {
                            if (treeDr["tname"] != null)
                            {
                                TreeNode node = new TreeNode(treeDr["tname"].ToString(), 1, 1);

                                item.Nodes.Add(node);
                            }

                        }
                    }
                }
                SetWindow();

            }
            catch
            {
                MessageBox.Show("Unable to connect to SQL Server!");
            }
        }

        void SetWindow()
        {
            treeView1.Visible = true;
            tabControl1.Visible = true;
            ConnectGroup.Visible = false;
            Width = 1050;
            Height = 600;
            menuStrip1.Visible = true;
        }

        #region Code Editors
        private void fctb_TextChanged(object sender, TextChangedEventArgs e)
        {
            //switch (lang)
            //{
            //    case "SQL":
            //        //For sample, we will highlight the syntax of C# manually, although could use built-in highlighter
            //        //CSharpSyntaxHighlight(e);//custom highlighting
            //        fctb.Language = Language.SQL;
            //        break;
            //    default:
            //        break;//for highlighting of other languages, we using built-in FastColoredTextBox highlighter
            //}
            fctb.Language = Language.SQL;
        }

        private void CSharpSyntaxHighlight(TextChangedEventArgs e)
        {
            fctb.LeftBracket = '(';
            fctb.RightBracket = ')';
            fctb.LeftBracket2 = '\x0';
            fctb.RightBracket2 = '\x0';
            //clear style of changed range
            e.ChangedRange.ClearStyle(BlueStyle, BoldStyle, GrayStyle, MagentaStyle, GreenStyle, BrownStyle);

            //string highlighting
            e.ChangedRange.SetStyle(BrownStyle, @"""""|@""""|''|@"".*?""|(?<!@)(?<range>"".*?[^\\]"")|'.*?[^\\]'");
            //comment highlighting
            e.ChangedRange.SetStyle(GreenStyle, @"//.*$", RegexOptions.Multiline);
            e.ChangedRange.SetStyle(GreenStyle, @"(/\*.*?\*/)|(/\*.*)", RegexOptions.Singleline);
            e.ChangedRange.SetStyle(GreenStyle, @"(/\*.*?\*/)|(.*\*/)", RegexOptions.Singleline | RegexOptions.RightToLeft);
            //number highlighting
            e.ChangedRange.SetStyle(MagentaStyle, @"\b\d+[\.]?\d*([eE]\-?\d+)?[lLdDfF]?\b|\b0x[a-fA-F\d]+\b");
            //attribute highlighting
            e.ChangedRange.SetStyle(GrayStyle, @"^\s*(?<range>\[.+?\])\s*$", RegexOptions.Multiline);
            //class name highlighting
            e.ChangedRange.SetStyle(BoldStyle, @"\b(class|struct|enum|interface)\s+(?<range>\w+?)\b");
            //keyword highlighting
            e.ChangedRange.SetStyle(BlueStyle, @"\b(abstract|as|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|do|double|else|enum|event|explicit|extern|false|finally|fixed|float|for|foreach|goto|if|implicit|in|int|interface|internal|is|lock|long|namespace|new|null|object|operator|out|override|params|private|protected|public|readonly|ref|return|sbyte|sealed|short|sizeof|stackalloc|static|string|struct|switch|this|throw|true|try|typeof|uint|ulong|unchecked|unsafe|ushort|using|virtual|void|volatile|while|add|alias|ascending|descending|dynamic|from|get|global|group|into|join|let|orderby|partial|remove|select|set|value|var|where|yield)\b|#region\b|#endregion\b");

            //clear folding markers
            e.ChangedRange.ClearFoldingMarkers();
            //set folding markers
            e.ChangedRange.SetFoldingMarkers("{", "}");//allow to collapse brackets block
            e.ChangedRange.SetFoldingMarkers(@"#region\b", @"#endregion\b");//allow to collapse #region blocks
            e.ChangedRange.SetFoldingMarkers(@"/\*", @"\*/");//allow to collapse comment block
        }

        private void fctb_AutoIndentNeeded(object sender, AutoIndentEventArgs args)
        {
            AutoIndent(args);
        }

        public static void AutoIndent(AutoIndentEventArgs args)
        {
            //block {}
            if (Regex.IsMatch(args.LineText, @"^[^""']*\{.*\}[^""']*$"))
                return;
            //start of block {}
            if (Regex.IsMatch(args.LineText, @"^[^""']*\{"))
            {
                args.ShiftNextLines = args.TabLength;
                return;
            }
            //end of block {}
            if (Regex.IsMatch(args.LineText, @"}[^""']*$"))
            {
                args.Shift = -args.TabLength;
                args.ShiftNextLines = -args.TabLength;
                return;
            }
            //label
            if (Regex.IsMatch(args.LineText, @"^\s*\w+\s*:\s*($|//)") &&
                !Regex.IsMatch(args.LineText, @"^\s*default\s*:"))
            {
                args.Shift = -args.TabLength;
                return;
            }
            //some statements: case, default
            if (Regex.IsMatch(args.LineText, @"^\s*(case|default)\b.*:\s*($|//)"))
            {
                args.Shift = -args.TabLength / 2;
                return;
            }
            //is unclosed operator in previous line ?
            if (Regex.IsMatch(args.PrevLineText, @"^\s*(if|for|foreach|while|[\}\s]*else)\b[^{]*$"))
                if (!Regex.IsMatch(args.PrevLineText, @"(;\s*$)|(;\s*//)"))//operator is unclosed
                {
                    args.Shift = args.TabLength;
                    return;
                }
        }

        private void DAL_TextChanged(object sender, TextChangedEventArgs e)
        {
            DAL.Language = Language.CSharp;
            CSharpSyntaxHighlight(e);
        }

        private void BLL_TextChanged(object sender, TextChangedEventArgs e)
        {
            BLL.Language = Language.CSharp;
            CSharpSyntaxHighlight(e);
        }

        private void BLL_AutoIndentNeeded(object sender, AutoIndentEventArgs e)
        {
            AutoIndent(e);
        }

        private void DAL_AutoIndentNeeded(object sender, AutoIndentEventArgs e)
        {
            AutoIndent(e);
        }
        #endregion

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            Generate.Enabled = (treeView1.SelectedNode.Level == 1 || treeView1.SelectedNode.Level == 0);
        }

        private void Generate_Click(object sender, EventArgs e)
        {
            if (treeView1.SelectedNode != null && treeView1.SelectedNode.Level == 1)
            {
                if (treeView1.SelectedNode != null)
                {
                    string connStr = GetConnectionString(Authentication.SelectedIndex);

                    string dbName = treeView1.SelectedNode.Parent.Text;
                    string tableName = treeView1.SelectedNode.Text;

                    string x = string.Format(Helper.TablesAndColumns, dbName);

                    string f = string.Format(Helper.ForeignKeys, dbName);

                    List<Sql> sqlList = Helper.GetTablesAndColumns(connStr, x);

                    List<ForeignKey> sqlListForeignKeys = Helper.GetForeignKeys(connStr, f);

                    foreach (var item in sqlListForeignKeys)
                    {
                        var temp = sqlList.Where(m => m.TableName == item.K_Table && m.ColumnName == item.FK_Column).SingleOrDefault();
                        if (temp != null)
                            temp.IsForeignKey = "1";
                        else
                            temp.IsForeignKey = "0";
                    }

                    GenerateSQL(dbName, tableName, sqlList);
                    //bool GenerateWrapperClass = bool.Parse(Session.LoadFromSession("GenerateWrapperClass").ToString());
                    //if (GenerateWrapperClass == true)
                    GenerateWrapperClassCSharp(tableName, sqlList, sqlListForeignKeys);
                }
            }

            if (treeView1.SelectedNode != null && treeView1.SelectedNode.Level == 0)
            {
                if (treeView1.SelectedNode != null)
                {
                    string connStr = GetConnectionString(Authentication.SelectedIndex);

                    string dbName = treeView1.SelectedNode.Text;
                    string x = string.Format(Helper.TablesAndColumns, dbName);

                    string f = string.Format(Helper.ForeignKeys, dbName);

                    List<Sql> sqlList = Helper.GetTablesAndColumns(connStr, x);

                    List<ForeignKey> sqlListForeignKeys = Helper.GetForeignKeys(connStr, f);
                    foreach (TreeNode tableName in treeView1.SelectedNode.Nodes)
                    {
                        foreach (var item in sqlListForeignKeys)
                        {
                            var temp = sqlList.Where(m => m.TableName == item.K_Table && m.ColumnName == item.FK_Column).SingleOrDefault();
                            if (temp != null)
                                temp.IsForeignKey = "1";
                            else
                                temp.IsForeignKey = "0";
                        }

                        GenerateSQL(dbName, tableName.Text, sqlList);
                        //bool GenerateWrapperClass = bool.Parse(Session.LoadFromSession("GenerateWrapperClass").ToString());
                        //if (GenerateWrapperClass == true)
                        GenerateWrapperClassCSharp(tableName.Text, sqlList, sqlListForeignKeys);
                    }
                }
            }
        }

        private void GenerateSQL(string DatabaseName, string tableName, List<Sql> rows)
        {
            string Prefix = "";//Session.LoadFromSession("Prefix").ToString();

            bool GenerateSelectAll = bool.Parse(Session.LoadFromSession("GenerateSelectAllProc").ToString());
            bool GenerateSelectRowByForeignKeyProc = bool.Parse(Session.LoadFromSession("GenerateSelectRowByForeignKeyProc").ToString());
            bool GenerateSelectRow = bool.Parse(Session.LoadFromSession("GenerateSelectRowProc").ToString());
            bool GenerateInsert = bool.Parse(Session.LoadFromSession("GenerateInsertProc").ToString());
            bool GenerateUpdate = bool.Parse(Session.LoadFromSession("GenerateUpdateProc").ToString());
            bool GenerateDelete = bool.Parse(Session.LoadFromSession("GenerateDeleteRowProc").ToString());
            bool SaveToFile = bool.Parse(Session.LoadFromSession("SaveToFile").ToString());
            bool GenEntity = bool.Parse(Session.LoadFromSession("GenEntity").ToString());


            if (GenerateSelectAll)
            {
                fctb.Text = SqlGenerator.CreateSelectAllSP(String.Format("{0}{1}SelectAllRows", Prefix, tableName), tableName, rows);
                fctb.Text += "\r\n\r\n";
            }

            if (GenerateSelectRowByForeignKeyProc)
            {
                string temp = SqlGenerator.CreateSelectByForeignKeySP(String.Format("{0}{1}SelectRow", Prefix, tableName), tableName, rows);
                if (temp != "")
                {
                    fctb.Text += temp;
                    fctb.Text += "\r\n\r\n";
                }
            }

            if (GenerateSelectRow)
            {
                fctb.Text += SqlGenerator.CreateSelectRowSP(String.Format("{0}{1}SelectRow", Prefix, tableName), tableName, rows);
                fctb.Text += "\r\n\r\n";
            }

            if (GenerateInsert)
            {
                fctb.Text += SqlGenerator.CreateInsertSP(Prefix + tableName + "InsertRow", tableName, rows);
                fctb.Text += "\r\n\r\n";
            }

            if (GenerateUpdate)
            {
                fctb.Text += SqlGenerator.CreateUpdateSP(Prefix + tableName + "UpdateRow", tableName, rows);
                fctb.Text += "\r\n\r\n";
            }

            if (GenerateDelete)
            {
                fctb.Text += SqlGenerator.CreateDeleteRowSP(Prefix + tableName + "DeleteRow", tableName, rows);
            }

            if (SaveToFile)
            {
                string Namespace = Session.LoadFromSession("Namespace").ToString();
                System.IO.StreamWriter file = new System.IO.StreamWriter(Namespace + "SQL." + tableName + ".sql");
                file.WriteLine(fctb.Text);
                file.Close();
            }
        }

        private void GenerateWrapperClassCSharp(string tableName, List<Sql> rows, List<ForeignKey> sqlListForeignKeys)
        {
            bool WrapperClass_GenerateStaticMethods = bool.Parse(Session.LoadFromSession("WrapperClass_GenerateStaticMethods").ToString());

            bool GenerateSelectAll = bool.Parse(Session.LoadFromSession("GenerateSelectAllProc").ToString());
            bool GenerateSelectRow = bool.Parse(Session.LoadFromSession("GenerateSelectRowProc").ToString());
            bool GenerateSelectRowByForeignKey = bool.Parse(Session.LoadFromSession("GenerateSelectRowByForeignKeyProc").ToString());
            bool GenerateInsert = bool.Parse(Session.LoadFromSession("GenerateInsertProc").ToString());
            bool GenerateUpdate = bool.Parse(Session.LoadFromSession("GenerateUpdateProc").ToString());
            bool GenerateDelete = bool.Parse(Session.LoadFromSession("GenerateDeleteRowProc").ToString());
            bool SaveToFile = bool.Parse(Session.LoadFromSession("SaveToFile").ToString());
            bool IsGenEntity = bool.Parse(Session.LoadFromSession("GenEntity").ToString());

            string methods = string.Empty;

            if (GenerateSelectAll)
            {
                DAL.Text = DalGenerator.SelectAllRows("SelectAll", tableName, WrapperClass_GenerateStaticMethods);
                BLL.Text = BllGenerator.SelectAllRows("SelectAll", tableName, rows, WrapperClass_GenerateStaticMethods, sqlListForeignKeys, IsGenEntity);
            }
            if (GenerateSelectRow)
            {
                DAL.Text += DalGenerator.SelectRow("SelectRow", tableName, rows, WrapperClass_GenerateStaticMethods);
                BLL.Text += BllGenerator.SelectRow("SelectRow", tableName, rows, WrapperClass_GenerateStaticMethods);
            }

            if (GenerateSelectRowByForeignKey)
            {
                string temp = DalGenerator.SelectRowByForeignKey("SelectRow", tableName, rows, WrapperClass_GenerateStaticMethods);
                if (temp != "")
                    DAL.Text += temp;
                temp = BllGenerator.SelectRowByForeignKey("SelectRow", tableName, rows, WrapperClass_GenerateStaticMethods);
                if (temp != "")
                    BLL.Text += temp;
            }

            if (GenerateInsert)
            {
                DAL.Text += DalGenerator.InsertRow("InsertRow", tableName, rows, WrapperClass_GenerateStaticMethods);
                BLL.Text += BllGenerator.InsertRow("InsertRow", tableName, rows, WrapperClass_GenerateStaticMethods);
            }

            if (GenerateUpdate)
            {
                DAL.Text += DalGenerator.UpdateRow("UpdateRow", tableName, rows, WrapperClass_GenerateStaticMethods);
                BLL.Text += BllGenerator.UpdateRow("UpdateRow", tableName, rows, WrapperClass_GenerateStaticMethods);
            }

            if (GenerateDelete)
            {
                DAL.Text += DalGenerator.DeleteRow("DeleteRow", tableName, rows, WrapperClass_GenerateStaticMethods);
                BLL.Text += BllGenerator.DeleteRow("DeleteRow", tableName, rows, WrapperClass_GenerateStaticMethods);
            }
            BLL.Text += "\t}\r\n}";
            if (SaveToFile)
            {
                string Namespace = Session.LoadFromSession("Namespace").ToString();
                DAL.Text = DAL.Text.Replace("FAP.DataAccess.", Namespace);
                BLL.Text = BLL.Text.Replace("FAP.DataAccess.", Namespace);

                System.IO.StreamWriter file = new System.IO.StreamWriter(Namespace + "DAL." + tableName + ".cs");
                file.WriteLine(DAL.Text);
                file.Close();

                file = new System.IO.StreamWriter(Namespace + "BLL." + tableName + ".cs");
                file.WriteLine(BLL.Text);
                file.Close();
            }

        }

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MainForm option = new MainForm();
            option.ShowDialog();
        }

        private void Cancel_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }
    }
}
